#include "../Include/MySqlDC.hpp"
#include "DataLayer/Include/ConnectionManager.hpp"

Supetronix::PersistO::DL::MySqlDC::MySqlDC()
{
}


Supetronix::PersistO::DL::MySqlDC::~MySqlDC()
{
	std::cout << "child destructor" << std::endl; 
}

void* Supetronix::PersistO::DL::MySqlDC::createConnection(const ConnectionDefinition* connDefinition)
{
	//create the sql driver instance
    std::cout << "connecting..." << std::endl;
    _mySqlDriver = get_driver_instance();
    
	//connect to sql server based on "connectionDefinition" provided by the user
    sql::Connection* con = _mySqlDriver->connect(connDefinition->ServerName(), connDefinition->UserID(), connDefinition->Password());

	//connect to the specific database
    con->setSchema(connDefinition->DatabaseName());
    
    return con;
}

Connection* Supetronix::PersistO::DL::MySqlDC::connect(ConnectionSourceName sourceName)
{
	//deprecated method for database connection
	/*
	std::cout << "connecting..." << std::endl;
	_mySqlDriver = get_driver_instance();

	sql::Connection* con = _mySqlDriver->connect("","","");
	con->setSchema("");
        
	return con;
	*/
	return nullptr;
}

ResultSet* Supetronix::PersistO::DL::MySqlDC::executeQuery(ConnectionSourceName sourceName, QueryType qryType, const string& query, const QueryModifierBase* modifier)
{
	string finalQuery = query;

	//if query is for "select, insert or update" then build the where clause. If query already have the a "where" clause then start with "and" clause
	switch (qryType)
	{
	case QueryType::Select:
	case QueryType::Update:
	case QueryType::Delete:
		//if where clause is not found then add <where> ... this is boost insensitive find
		if ( !ifind_last(query, "where") )
			finalQuery += " WHERE " + QueryBuilder::BuildWhereClause( modifier );
		else
			finalQuery += " AND " + QueryBuilder::BuildWhereClause( modifier );

		break;
	}

	//once where clause is constructed then replace the parameter names with the provider specifc tags
	QueryBuilder::TransformQueryParameters(finalQuery, ConnectionSourceType::MySQL);
    
	//once the query is transformed to provider specific syntax then call the provder substitute the parameter values and execute the query
	return buildQuery(sourceName, finalQuery, modifier)->executeQuery();
}

std::unique_ptr<sql::PreparedStatement> Supetronix::PersistO::DL::MySqlDC::buildQuery(ConnectionSourceName sourceName, const string& query, const QueryModifierBase* modifier)
{
	//get the connection from ConnectionManager
    const sql::Connection* conn = ConnectionManager<sql::Connection>::AcquireConnection(sourceName, this);

	//prepare the query and set the parameters
    std::unique_ptr<sql::PreparedStatement> stmt( const_cast<sql::Connection*>(conn)->prepareStatement(query));
    shared_ptr<vector<ParameterInfo>> filterData = modifier->getParameterList();
    unsigned int paramIndex = 1;

    if ( !filterData->empty() )
    {
        //filterData->begin()->ParameterName;
        //build the where clause part of the SQL
        for( auto& filter : *filterData )
        {
			//currently the code is only assigning the integer values to the parameters. Helper methods are in the "Common/Helper" class to check the data type
			//of each value and assign it to prepared statement
            if ( Helper::isInteger( filter.ParameterValue) )
            {
                    stmt->setInt(paramIndex++, Helper::toInteger(filter.ParameterValue));
            }
        }
    }


    return stmt;
}
